#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include "ThreadPool.hpp"
#include "Log.hpp"
#include "Task.hpp"
#include "Daemon.hpp"

class tcpServer;

Log logger;
enum
{
    Usage_Err = 1,
    Socket_Err = 2,
    Bind_Err,
    Listen_Err
};

const int defaultfd = -1;
std::string defaultip = "0.0.0.0";
const int backlog = 10;

// 设置线程信息
class ThreadData
{
public:
    ThreadData(int fd, const std::string &ip, const uint16_t &port, tcpServer *t)
        : sockfd(fd), clientip(ip), clientport(port), tsvr(t)
    {}

public:
    int sockfd;
    std::string clientip;
    uint16_t clientport;
    tcpServer *tsvr;
};

// 面向连接，字节流
class tcpServer
{
public:
    tcpServer(const uint16_t &port, const std::string &ip = defaultip)
        : _listensock(defaultfd), _ip(ip), _port(port)
    {
    }
    void Init()
    {
        // 1.创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logger(Fatal, "create socket errno: %d,errstring: %s", errno, strerror(errno));
            exit(Socket_Err);
        }
        logger(Info, "create sockfd success,sockfd:%d", _listensock);

        // 防止偶发性的服务器无法立即重启（tcp协议）
        int opt=1;
        setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));

        // 2.绑定套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY; // 也可如下写法
        // inet_aton(_ip.c_str(),&(local.sin_addr));       //字符串IP地址转换为一个32位的网络序列IP地址

        if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logger(Fatal, "bind error,errno: %d,errstring: %s", errno, strerror(errno));
            exit(Bind_Err);
        }
        logger(Info, "bind socket success,sockfd: %d", _listensock);

        if (listen(_listensock, backlog) < 0)
        {
            logger(Fatal, "listen error,errno: %d,errstring: %s", errno, strerror(errno));
            exit(Listen_Err);
        }
        logger(Info, "listen socket success,sockfd: %d", _listensock);
    }

    /*  多线程版
    // static方式无法使用类内非static成员方法
    static void *Routine(void *args) // 成员函数内部都有一个this指针，添加static
    {
        // pthread_detach()：将该线程设为分离状态。pthread_self()：获取当前线程的 ID。
        pthread_detach(pthread_self());

        ThreadData *td = static_cast<ThreadData *>(args); // 形参void*转为ThreadData*

        td->tsvr->Service(td->sockfd, td->clientip, td->clientport); // 执行的服务（任务）
        delete td;
        return nullptr;
    }
    */

    void Start()
    {
        //Daemon();                         //守护进程化
        //signal(SIGPIPE,SIG_IGN);        //忽略 SIGPIPE 信号，防止程序在写入已关闭的 socket 时崩溃。
        ThreadPool<Task>::GetInstance()->Start();
        //signal(SIGCHLD, SIG_IGN);  
        logger(Info, "tcpServer is running....");
        for (;;)
        {
            // 获取新连接 
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                logger(Warrning, "accept error,errno: %d,errstring: %s", errno, strerror(errno));
                continue;
            }
            char clientip[32];
            uint16_t clientport = ntohs(client.sin_port);                       // 获取客户端的端口号
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip)); // 获取客户ip并转为主机序列

            // 根据新连接来进行通信,提供服务
            logger(Info, "get a new link...,sockfd: %d, client ip: %s, client port: %d\n", sockfd, clientip, clientport);

            // version 1,单进程
            // Service(sockfd,clientip,clientport);
            // close(sockfd);

            // version 2,多进程，父进程和孙子进程同时执行
            /*
            pid_t id=fork();

            //子进程
            if(id==0)
            {
                close(_listensock);             //关闭父进程文件描述符

                //子进程创建孙子进程后，子进程退出是为了被父进程早点等待成功而不阻塞，由孙子进程执行具体任务
                if(fork()>0) exit(0);
                Service(sockfd,clientip,clientport);
                close(sockfd);
                exit(0);
            }

            //父进程
            close(sockfd);                      //关闭子进程的文件描述符
            pid_t rid=waitpid(id,nullptr,0);
            (void)rid;
            */

            // version 3,多线程,主线程获取新链接，新线程执行任务
            /*
            ThreadData *td=new ThreadData(sockfd,clientip,clientport,this);
            pthread_t pid;
            pthread_create(&pid,nullptr,Routine,td);
            */
       
        // version 4 线程池
        Task t(sockfd,clientip,clientport);
        ThreadPool<Task>::GetInstance()->push(t);
        }

    }

    /*
    // 读写数据
    void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)
    {
        // 测试返回数据
        char buf[4096];
        while (1)
        {
            ssize_t n = read(sockfd, buf, sizeof(buf));
            if (n > 0)
            {
                buf[n] = 0;
                std::cout << "client say# " << buf << std::endl;
                std::string echo_string = "tcpserver echo# ";
                echo_string += buf;
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0) // 客户端退出
            {
                logger(Info, "%s:%d quit,server close sockfd: %d", clientip.c_str(), clientport, sockfd);
                break;
            }
            else
            {
                logger(Warrning, "read error,sockfd: %d,client ip: %d,client port: %d", sockfd, clientip.c_str(), clientport);
                break;
            }
        }
    }
    */

    ~tcpServer()
    {
    }

private:
    int _listensock; // 网络文件描述符
    std::string _ip; // 任意地址bind 0
    uint16_t _port;  // 服务器进程端口号
};

 